//----------------------- Kings ------------------------------------------------------- // #1 - P1 or P2 (define "SitesKings" (sites Occupied by:#1 component:"King") ) (define "CountSpartanKings" (count Sites in:("SitesKings" P2)) ) // Here's a curious thing. The victory conditions for the Persians and Spartans are different. // Furthermore the Persian victory conditions depend on how many Kings the Spartans happen to have. // However with a suitable definition we can unify and simplify them into something logically equivalent // and it seems an obvious implementation trick to do this. // // We define "Omnicheck" as: A player is in omnicheck if all the Kings they happen to have on the board at the time are in check. // // Then the rules can be stated as follows: // 1. It is illegal to move into omnicheck. // 2. If a player is in omnicheck, they must move out of omnicheck on their next turn. // 3. If a player is in omnicheck and cannot move out of omnicheck, they have lost. // #1 - P1 or P2 (define "IsInOmnicheck" (all Sites ("SitesKings" #1) if:(is Threatened at:(site))) ) (define "NextCanNotMove" (not (can Move (do (forEach Piece Next) ifAfterwards:(not ("IsInOmnicheck" Next))))) ) //----------------------- Castling ------------------------------------------------------- (define "KingPosition" 4) (define "RookLeft" 0) (define "RookRight" 7) (define "KingInTheInitialPlace" (= (what at:("KingPosition")) (id "King" Mover)) ) // #1 - site (define "HasNeverMoved" (= (state at:#1) 1) ) (define "PieceHasMoved" (set State at:(last To) 0) ) (define "RememberPieceHasMoved" (then (if (= (state at:(last To)) 1) "PieceHasMoved" ) ) ) (define "KingNotCheckedAndToEmpty" (and (is Empty (to)) (not ("IsInCheck" "King" Mover at:(to))) ) ) // This macro defines one piece move of a castling manoeuvre // #1 - (from) but specified explicitly // #2 - direction (E or W) // #3 - number of spaces to move // #4 - condition to check during slide // #5 - then clause (define "DoCastle" (move Slide (from #1) #2 (between (exact #3) if:#4 ) #5 ) ) (define "SmallCastling" ("DoCastle" "KingPosition" E 2 "KingNotCheckedAndToEmpty" (then (and ("PieceHasMoved") ("DoCastle" "RookRight" W 2 True)))) ) (define "BigCastling" ("DoCastle" "KingPosition" W 2 "KingNotCheckedAndToEmpty" (then (and ("PieceHasMoved") ("DoCastle" "RookLeft" E 3 True)))) ) //----------------------- Non-Pawn Pieces ------------------------------------------------------- (define "CaptureToPieceAndResetCounter" (apply (if ("IsEnemyAt" (to)) (remove (to) (then (set Counter)) ) ) ) ) // #1 - direction // #2 - optional remember clause (define "SlideMove" (move Slide #1 (to if:("IsEnemyAt" (to)) "CaptureToPieceAndResetCounter" ) #2 ) ) // #1 - direction // #2 - optional remember clause (define "StepMove" (move Step #1 (to if:(not ("IsFriendAt" (to))) "CaptureToPieceAndResetCounter" ) #2 ) ) // #1 - direction (define "HopMove" (move Hop #1 (to if:(or ("IsEnemyAt" (to)) (is Empty (to))) "CaptureToPieceAndResetCounter" ) ) ) (define "KnightMove" (move Leap "KnightWalk" (to if:(not ("IsFriendAt" (to))) "CaptureToPieceAndResetCounter" ) ) ) //----------------------- Pawns and Hoplites ------------------------------------------------------- // #1 - Directions // #2 - between clause (define "PawnDoubleMove" (move Hop #1 #2 (to if:(is Empty (to))) ) ) // #1 - Directions (define "PawnCapture" (move Step #1 (to if:("IsEnemyAt" (to)) (apply (remove (to))) ) ) ) // #1 - Directions (define "PawnMove" (move Step #1 (to if:(is Empty (to))) ) ) (define "PawnPromotion" (then (and (if (is In (last To) (sites Mover "Promotion")) (moveAgain) ) (set Counter) ) ) ) (define "PawnDirections" (directions { FL FR })) //----------------------- Core ------------------------------------------------------- (game "Spartan Chess" ("TwoPlayersNorthSouth") (equipment { (board (square 8)) (piece "Pawn" P1 (or { (if (is In (from) (sites Start (piece (what at:(from))))) ("PawnDoubleMove" Forward (between if:(is Empty (between)))) ) ("PawnMove" Forward) ("PawnCapture" ("PawnDirections")) } ("PawnPromotion") ) ) (piece "Hoplite" P2 (or { (if (is In (from) (sites Start (piece (what at:(from))))) ("PawnDoubleMove" ("PawnDirections")) ) ("PawnMove" ("PawnDirections")) ("PawnCapture" Forward) } ("PawnPromotion") ) ) (piece "Rook" P1 ("SlideMove" Orthogonal "RememberPieceHasMoved") ) (piece "General" P2 (or ("SlideMove" Orthogonal) ("StepMove" Diagonal) ) ) (piece "Warlord" P2 (or ("SlideMove" Diagonal) ("KnightMove") ) ) (piece "Lieutenant" P2 (or { ("StepMove" Diagonal) ("HopMove" Diagonal) (move Step (directions { W E }) (to if:(is Empty (to)) ) ) }) ) (piece "Captain" P2 (or ("StepMove" Orthogonal) ("HopMove" Orthogonal) ) ) (piece "King" Each ("StepMove" Adjacent ("RememberPieceHasMoved")) ) (piece "Bishop" P1 ("SlideMove" Diagonal) ) (piece "Knight" P1 ("KnightMove") ) (piece "Queen" P1 ("SlideMove") ) (regions "Promotion" P1 (sites Top)) (regions "Promotion" P2 (sites Bottom)) } ) (rules (start { (place "Pawn1" (sites Row 1)) (place "Hoplite2" (sites Row 6)) (place "Rook1" {"A1" "H1"} state:1) (place "Knight1" {"B1" "G1"}) (place "Bishop1" {"C1" "F1"}) (place "Queen1" coord:"D1") (place "King1" coord:"E1" state:1) (place "Lieutenant2" {"A8" "H8"}) (place "Warlord2" {"G8"}) (place "General2" {"B8"}) (place "King2" {"C8" "F8"} state:0) (place "Captain2" {"D8" "E8"}) } ) (play (if "SameTurn" (if (= (mover) (id P1)) (move Promote (last To) (piece {"Queen" "Knight" "Bishop" "Rook"}) Mover) (if (= 1 ("CountSpartanKings")) (move Promote (last To) (piece {"King" "Captain" "General" "Warlord" "Lieutenant"}) Mover) (move Promote (last To) (piece {"Captain" "General" "Warlord" "Lieutenant"}) Mover) ) ) (do (or (forEach Piece) (if (and { "KingInTheInitialPlace" // This will filter out Spartan castling, because they have state 0 ("HasNeverMoved" "KingPosition") (not ("IsInCheck" "King" Mover)) }) (or (if (and ("HasNeverMoved" "RookLeft") (can Move ("DoCastle" "RookLeft" E 3 (is Empty (to)))) ) "BigCastling" ) (if (and ("HasNeverMoved" "RookRight") (can Move ("DoCastle" "RookRight" W 2 (is Empty (to)))) ) "SmallCastling" ) ) ) ) ifAfterwards:(not ("IsInOmnicheck" Mover)) ) ) ) (end { (if (and ("IsInOmnicheck" Next) ("NextCanNotMove") ) (result Mover Win) ) (if (or (no Moves Mover) (= (counter) 100)) (result Mover Draw)) } ) ) ) //------------------------------------------------------------------------------ (metadata (info { (description "Spartan Chess is a chess variant played on a standard 8x8 chess board. The two sides have pieces and pawns with different characteristics and capabilities. Such differences you would expect between opponents on an actual ancient battlefield. The Black side represents the Spartans and the White the Persians. The Persians have pawns, pieces, an initial placement and move in accord with the rules of orthodox chess. The Spartans have two Kings and except their Kings, every Spartan playing piece moves differently from any piece found in orthodox chess.") (rules "The Pieces - White (the Persians) has orthodox chess pieces in standard spaces: 2 Rooks (A1, H1); 2 Knights (B1, G1); 2 Bishops (C1, F1); 1 Queen (D1); 1 King (E1); 8 Pawns (A2-H2). - Black (the Spartans) has: 2 Lieutenants (A8, H8); 1 General (B8); 1 Warlord (G8); 2 Kings (C8, F8); 2 Captains (D8, E8); 8 Hoplites (A7-H7). The Moves - Pawns can move (but not capture) one space forward. On their first move they can move two spaces forward. They capture one space diagonally forward. There is no en passant rule. - Rooks can move and capture any number of spaces orthogonally. - Bishops can move and capture any number of spaces diagonally. - Knights can move one space orthogonally with one space forward diagonally leaping over intervening pieces and capturing what they land on. - The Queen can move and capture any number of spaces orthogonally or diagonally. - Kings can move and capture one space orthogonally or diagonally. - Lieutenants (shown as crosses) can move and capture diagonally upto two spaces, jumping over any piece if necessary. They can also move (but not capture) one space sideways. - The General (shown as an upside-down rook) can move and capture any number of spaces orthogonally or one space diagonally. - The Warlord (shown as an upside-down bishop) can move and capture any number of spaces diagonally or like a knight. - Captains (shown as squares) can move and capture upto spaces orthogonally and may jump if necessary. - Hoplites (shown as an upside-down pawns) can move (but not capture) one space diagonally forward. On their first move they can move two spaces diagonally forward, jumping if necessary. They capture one space forward. Winning The Spartan and Persian have different victory conditions. Spartan Victory: The Spartan wins when the Persian King is checkmated as in orthodox chess. Persians Victory: The Persian wins once one of the Spartan Kings is captured and the remaining Spartan King is checkmated or when both Spartan Kings are placed under simultaneous attack (duple-check) and neither King can be removed from attack on the next move (Duple-Check and Mate). First Move The Persians, being the aggressors historically and White, always move first. Check Immunity When the Spartan has two Kings in play a Spartan King is immune from check. Thus, the Spartan may move a King onto an enemy attacked square, leave a King under attack or move a piece that would expose a King to attack. Duple-Check & Mate If both Spartan Kings are placed under simultaneous attack this is a form of check called duple-check. It is illegal for the Spartan to make a move that will place both of his Kings underattack. With both Kings under attack, the Spartan loses if on his move he is unable to remove at least one King from attack. In such case the game ends in checkmate. Promotion A hoplite, upon reaching its 8th rank, may promote to any Spartan piece including a King but only if the Spartan has only one king in play. A pawn, upon reaching its 8th rank, may promote to any Persian piece apart from the King. Capturing en passant There is no capturing en passant in Spartan Chess. Castling Spartan Kings may not castle. Persian Kings may castle as normal.") (id "1396") (source "BGG") (version "1.3.12") (classification "board/war/replacement/checkmate/chess") (author "Steven Streetman") (credit "Nicholas Bamber (building on Eric Piette's implementation of chess)") (date "2010") } ) (graphics { (player Name P1 "Persians") (player Name P2 "Spartans") (piece Rename piece:"Hoplite" "pawn") (piece Rotate P2 "Hoplite" degrees:180) (piece Rename piece:"Lieutenant" "cross") (piece Rename piece:"Captain" "square") (piece Rename piece:"General" "rook") (piece Rotate P2 "General" degrees:180) (piece Rename piece:"Warlord" "bishop") (piece Rotate P2 "Warlord" degrees:180) (show Check "King") (piece Scale "Pawn" 0.825) (piece Scale "Hoplite" 0.825) (piece Families {"Defined" "Microsoft" "Pragmata" "Symbola"}) (board Style Chess) }) (ai "Spartan Chess_ai" ) )